package cn.linran.exception;

import cn.linran.enums.GlobalErrorCode;
import cn.linran.result.JSONResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.util.List;

/**
 * 全局统一异常处理
 */
// 全局统一异常注解，此注解下包含：ResponseBody+ControllerAdvice，方法返回值会封装为JSON
//@ControllerAdvice注解,全局捕获异常类,只要作用在@RequestMapping上,所有的异常都会被捕获
@RestControllerAdvice
// 日志器注解
@Slf4j
public class GlobalExceptionHandler {
    /**
     * 全局系统异常处理方法，捕捉Exception异常
     * @param e
     * @return
     */
    @ExceptionHandler(value = Exception.class)
    public JSONResult exceptionHandler(Exception e){
        e.printStackTrace();
        // 1.打印日志
        log.error("发生系统异常，异常信息为：" + e.getMessage());
        // 2.返回异常信息
        return JSONResult.error(GlobalErrorCode.SERVICE_ERROR);
    }

    /**
     * 全局业务异常,捕捉自定义异常GlobalCustomException
     * @param e
     * @return
     */
    @ExceptionHandler(value = GlobalCustomException.class)
    public JSONResult GlobalCustomExceptionHandler(GlobalCustomException e){
        System.out.println("e.printStackTrace:");
        e.printStackTrace();//cn.linran.exception.GlobalCustomException: 用户名称不合法！...

        // 1.打印日志:2022-08-26 11:39:17.185 ERROR 29736 --- [io-10021-exec-1] c.l.exception.GlobalExceptionHandler     : 发生业务异常，异常码：50001, 异常信息：用户名称不合法！
        log.error("发生业务异常，异常码：{}, 异常信息：{}", e.getErrorCode(), e.getErrorMessage());
        // 2.返回异常信息
        return JSONResult.error(e.getErrorMessage(), e.getErrorCode());
    }

    /**
     * 自定义全局参数异常,参数校验结果异常Bean validation【JSR303】
     * @param e
     * @return
     */
    @ExceptionHandler(value = MethodArgumentNotValidException.class)
    public JSONResult methodArgumentNotValidExceptionHandler(MethodArgumentNotValidException e){
        e.printStackTrace();
        // 1.打印日志
        log.error("发生方法参数校验异常，异常信息为：" + e.getMessage());
        // 2.返回异常信息，异常信息我们需要获取到我们自定义的字段提示语
        // 2.1.得到所有的字段异常提示信息
        List<ObjectError> allErrors = e.getBindingResult().getAllErrors();
        StringBuffer sbf = new StringBuffer();
        sbf.append("参数校验失败，失败原因为：");
        // 2.2.遍历得到所有异常提示语
        allErrors.forEach(objectError -> sbf.append(objectError.getDefaultMessage()).append("；"));
        return JSONResult.error(sbf.toString());
    }

}